                    (********************************)
                    (*             TList            *)
                    (*  --------------------------  *)
                    (*  v 1.1.0                     *)
                    (*  2011-08-30                  *)
                    (*  (c) by Jardo                *)
                    (********************************)

unit uList;

interface

type

  TListItemContainer = class
  private
    aNext: TListItemContainer;
    aItem: TObject;
    procedure SetNext(paNext: TListItemContainer);
    function  GetNext:TListItemContainer;
  public
    constructor Create(paItem: TObject);
    function    GetItem:TObject;
    procedure   SetItem(paItem: TObject);
    property    Next:TListItemContainer read GetNext write SetNext;
    property    Item:TObject read GetItem write SetItem;
  end;

  TList = class
  private
    aFirst,
    aLast,
    aIteration: TListItemContainer;
    aItemCount: cardinal;
    aOwnItems:  boolean;

    function    GetContainerAt(paIndex:cardinal):TListItemContainer;

  public
    constructor Create;
    destructor  Destroy; override;

    function  Add(paItem: TObject):cardinal;
    procedure Clear;

    //Queue methods
    procedure QueueIn(paItem: TObject);
    function  QueueOut: TObject;

    //stack methods
    procedure StackIn(paItem: TObject);
    function  StackOut: TObject;

    function  IsEmpty: boolean;
    function  Count:cardinal;
    function  At(paIndex: cardinal):TObject;
    function  First: TObject;
    function  Last:  TObject;

    function  Switch(paFirstIndex, paSecondIndex: cardinal):boolean;

    property OwnItems:boolean read aOwnItems write aOwnItems;
    property Items[paIndex: cardinal]:TObject read At; default;
  end;

  TListIterator = class
  private
    aList: TList;
  public
    constructor Create(paList: TList);
    function    HasNext:boolean;
    function    Next:TObject;
    procedure   Reset;
  end;

implementation

{ TListItemContainer }

constructor TListItemContainer.Create(paItem: TObject);
begin
  inherited Create;
  aItem := paItem;
end;

function TListItemContainer.GetItem: TObject;
begin
  result := aItem;
end;

function TListItemContainer.GetNext: TListItemContainer;
begin
  result := aNext;
end;

procedure TListItemContainer.SetItem(paItem: TObject);
begin
  aItem := paItem;
end;

procedure TListItemContainer.SetNext(paNext: TListItemContainer);
begin
  aNext := paNext;
end;

{ TList }

function TList.Add(paItem: TObject): cardinal;
var container:TListItemContainer;
begin
  container := TListItemContainer.Create(paItem);
  result := aItemCount;

  if aFirst = nil then
  begin
    aFirst := container;
    aLast  := container;
    aItemCount := 1;
  end
  else
  begin
    aLast.Next := container;
    aLast := container;
    inc(aItemCount);
  end;

end;

function TList.At(paIndex: cardinal): TObject;
var
  container: TListItemContainer;
begin
  result := nil;

  container := GetContainerAt(paIndex);
  if container<>nil then
    result := container.Item;
end;

procedure TList.Clear;
var container:TListItemContainer;
begin
  while aFirst <> nil do
  begin
    container := aFirst.Next;
    if aOwnItems then
      aFirst.GetItem.Free;
    aFirst.Destroy;
    aFirst := container;
  end;

  aFirst := nil;
  aLast  := nil;
  aItemCount := 0;
end;

function TList.Count: cardinal;
begin
  result := aItemCount;
end;

constructor TList.Create;
begin
  aFirst := nil;
  aLast  := nil;
  aIteration := nil;
  aItemCount := 0;
  aOwnItems := false;
end;

destructor TList.Destroy;
begin
  Clear;
  inherited;
end;

function TList.First: TObject;
begin
  if aFirst <> nil then
    result := aFirst.GetItem
  else
    result := nil;
end;

function TList.GetContainerAt(paIndex: cardinal): TListItemContainer;
var
  i: cardinal;
  container: TListItemContainer;
begin
  result := nil;

  if paIndex >= aItemCount then
    exit;

  i := 0;
  container := aFirst;
  while container <> nil do
  begin
    if i = paIndex then
    begin
      result := container;
      break;
    end;
    inc(i);
    container := container.Next;
  end;

end;

function TList.IsEmpty: boolean;
begin
  result := aItemCount = 0;
end;

function TList.Last: TObject;
begin
  if aLast <> nil then
    result := aLast.GetItem
  else
    result := nil;
end;

procedure TList.QueueIn(paItem: TObject);
begin
  Add(paItem);
end;

function TList.QueueOut: TObject;
var second: TListItemContainer;
begin
  if aFirst = nil then
    result := nil
  else
  begin
    result := aFirst.Item;
    second := aFirst.Next;
    aFirst.Destroy;
    aFirst := second;
    dec(aItemCount);
  end;
end;

procedure TList.StackIn(paItem: TObject);
begin
  Add(paItem);
end;

function TList.StackOut: TObject;
var container: TListItemContainer;
begin
  result := nil;

  if aFirst = nil then
    exit;

  if aFirst = aLast then
  begin
    result := aLast.Item;
    aLast.Destroy;
    aLast := nil;
    aFirst := nil;
  end
  else begin
    container := aFirst;
    while container.Next <> aLast do
      container := container.Next;
    result := aLast.Item;
    aLast.Destroy;
    container.Next := nil;
    aLast := container;
  end;

end;

function TList.Switch(paFirstIndex, paSecondIndex: cardinal): boolean;
var
 firstContainer, secondContainer: TListItemContainer;
 item:TObject;
begin
  result := false;
  if (paFirstIndex >= aItemCount)or(paSecondIndex >= aItemCount) then
    exit;

  firstContainer := GetContainerAt(paFirstIndex);
  secondContainer := GetContainerAt(paSecondIndex);

  item := firstContainer.Item;
  firstContainer.Item := secondContainer.Item;
  secondContainer.Item := item;

  result := true;
end;

{ TListIterator }

constructor TListIterator.Create(paList: TList);
begin
  inherited Create;
  aList := paList;
  Reset;
end;

function TListIterator.HasNext: boolean;
begin
  result := aList.aIteration <> nil;
end;

function TListIterator.Next: TObject;
begin
  result := aList.aIteration.GetItem;
  aList.aIteration := aList.aIteration.Next;
end;

procedure TListIterator.Reset;
begin
  aList.aIteration := aList.aFirst;
end;

end.
